package net.onceface.application.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.inject.Named;

import net.onceface.application.CartApplication;
import net.onceface.application.assembler.CartAssembler;
import net.onceface.application.assembler.FeatureAssembler;
import net.onceface.application.commons.InvokeResult;
import net.onceface.application.commons.Message;
import net.onceface.application.dto.CartDTO;
import net.onceface.application.dto.DisCountDTO;
import net.onceface.application.dto.FeatureDTO;
import net.onceface.core.domain.Cart;
import net.onceface.core.domain.Product;
import net.onceface.core.domain.Spec;

import org.springframework.transaction.annotation.Transactional;

@Named
@Transactional
public class CartApplicationImpl implements CartApplication {

	@Override
	public Map<String, Object> getCartPrice(Long clientId, Long disCountId) {
		List<CartDTO> carts = getCartByClientId(clientId);
		return countCart(carts, null);
	}
	
	public Map<String, Object> getCartDetails(Long clientId){
		Map<String, Object> map = new HashMap<String, Object>();
		List<CartDTO> carts = getCartByClientId(clientId);
		map.put("carts", carts);
		map.putAll(countCart(carts, null));
		return map;
	}
	
	/**
	 * 按用户ID获取用户购物车
	 * **/
	public static List<CartDTO> getCartByClientId(Long clientId) {
		List<Cart> carts = Cart.findByClientId(clientId);
		if(carts == null) return null;
		for(Cart cart : carts){
			if(cart.isValid()){
				if(cart.getSpecID() != null && cart.getSpecID() > 0){
					Spec spec = Spec.getValidSpecById(cart.getSpecID());
					if(spec == null || spec.getStock() < 1){
						cart.setValid(false);
						cart.setChecked(false);
						cart.save();
					}
				}else{
					Product product = Product.getValidProductById(cart.getProductId());
					if(product == null || product.getStock() < 1){
						cart.setValid(false);
						cart.setChecked(false);
						cart.save();
					}else{
						if(cart.getQuantity() > product.getStock()){
							cart.setQuantity(product.getStock());
							cart.save();
						}
					}
				}
			}
		}
		return CartAssembler.toDTOs(carts);
	}

	@Override
	public InvokeResult addProduct(Long clientId, Long specId, Long productId, int quantity){
		Product product = Product.get(Product.class, productId);
		Spec spec = null;
		int stock = 0;
		if(specId != null){
			spec = Spec.get(Spec.class, specId);
			stock = spec.getStock();
		}else{
			stock = product.getStock();
		}
		Cart cart = CartAssembler.toAddCartObject(clientId, product, spec, quantity);
		if(cart != null){
			cart.save();
			return InvokeResult.success(countCart(getCartByClientId(clientId), null));
		}else{
			return InvokeResult.failure(Message.GET_STOCK_MESSAGE + stock + "了！");
		}
	}

	@Override
	public InvokeResult editQuantity(Long clientId, Long id, int quantity) {
		Cart cart = Cart.get(Cart.class, id);
		if(cart.getSpecID() != null && cart.getSpecID() > 0){
			Spec spec = Spec.get(Spec.class, cart.getSpecID());
			if((spec.getStock() - quantity) < 1){
				return InvokeResult.failure(Message.GET_STOCK_MESSAGE + spec.getStock() + "了！");
			}
			cart.setQuantity(quantity);
		}else{
			Product product = Product.get(Product.class, cart.getProductId());
			if((product.getStock() - quantity) < 1){
				return InvokeResult.failure(Message.GET_STOCK_MESSAGE + product.getStock() + "了！");
			}
			cart.setQuantity(quantity);
		}
		return InvokeResult.success(countCart(getCartByClientId(clientId), null));
	}

	@Override
	public InvokeResult checked(Long clientId, Long id) {
		Cart cart = Cart.get(Cart.class, id);
		if(cart == null){
			return InvokeResult.failure(Message.ILLEGAL_OPERATION);
		}
		if(cart.isChecked()){
			cart.setChecked(false);
		}else{
			if(cart.getSpecID() != null && cart.getSpecID() > 0){
				Spec spec = Spec.get(Spec.class, cart.getSpecID());
				if((spec.getStock() - cart.getQuantity()) < 1){
					return InvokeResult.failure(Message.GET_STOCK_MESSAGE + spec.getStock() + "了！");
				}
				cart.setChecked(true);
			}else{
				Product product = Product.getValidProductById(cart.getProductId());
				if(product == null){
					return InvokeResult.failure(Message.NOT_SALE_PRODUCT);
				}
				if((product.getStock() - cart.getQuantity()) < 1){
					return InvokeResult.failure(Message.GET_STOCK_MESSAGE + product.getStock() + "了！");
				}
				cart.setChecked(true);
			}
			cart.save();
		}
		return InvokeResult.success(countCart(getCartByClientId(clientId), null));
	}

	@Override
	public InvokeResult checkedAll(Long clientId, boolean check) {
		List<Cart> carts = Cart.findByClientId(clientId);
		if(check && carts.size() > 0){
			for(Cart cart : carts){
				cart.setChecked(true);
				cart.save();
			}
		}
		if(!check && carts.size() > 0){
			for(Cart cart : carts){
				cart.setChecked(false);
				cart.save();
			}
		}
		return InvokeResult.success(countCart(getCartByClientId(clientId), null));
	}

	@Override
	public InvokeResult remove(Long clientId, Long id) {
		Cart cart = Cart.get(Cart.class, id);
		if(cart == null){
			return InvokeResult.failure(Message.ILLEGAL_OPERATION);
		}
		cart.remove();
		return InvokeResult.success(countCart(getCartByClientId(clientId), null));
	}

	/**
	 * 计算出购物车的优惠信息和价格
	 * **/
	public static Map<String, Object> countCart(List<CartDTO> cartDTOs, Long id) {
		Map<String, Object> countCart = new HashMap<String, Object>();
		double totalPrice = 0;
		double disCountPrice = 0;
		double price = 0;
		if(cartDTOs != null){
			List<FeatureDTO> features = new ArrayList<FeatureDTO>();
			Set<DisCountDTO> disCounts = new HashSet<DisCountDTO>();
			for(CartDTO cartDTO : cartDTOs){
				if(cartDTO.isChecked() && cartDTO.isValid()){
					totalPrice += cartDTO.getProductPrice() * cartDTO.getQuantity();
					Product product = Product.getProductFeatureById(cartDTO.getProductId());
					if(product.getFeatures().size() > 0)
					for(FeatureDTO feature : FeatureAssembler.toDTOs(product.getFeatures())){
						if(features.size() > 0){
							for(int b = 0; b < features.size(); b++){
								if(feature.getId() == features.get(b).getId()){
									features.get(b).setMoney(features.get(b).getMoney() + cartDTO.getProductPrice() * cartDTO.getQuantity());
									features.get(b).setQuantity(features.get(b).getQuantity() + cartDTO.getQuantity());
									break;
								}
								if(b + 1 == features.size()){
									feature.setMoney(cartDTO.getProductPrice() * cartDTO.getQuantity());
									feature.setQuantity(cartDTO.getQuantity());
									features.add(feature);
								}
							}
						}else{
							feature.setMoney(cartDTO.getProductPrice() * cartDTO.getQuantity());
							feature.setQuantity(cartDTO.getQuantity());
							features.add(feature);
						}
					}
				}
			}
			price = totalPrice;
			if(features.size() > 0 && disCountPrice == 0){
				for(int a = 0; a < features.size(); a++){
					if(features.get(a).getFirstDiscount() != null){
						if(features.get(a).getFirstDiscount().getType() == 1){
							if(features.get(a).getMoney() >= features.get(a).getFirstDiscount().getThreshold()){
								if(disCountPrice == 0 && (id == null || id == 0)){
									price = totalPrice - features.get(a).getFirstDiscount().getDisCount();
									disCountPrice = features.get(a).getFirstDiscount().getDisCount();
									features.get(a).getFirstDiscount().setDefDisCount(true);
								}else if(disCountPrice == 0 && features.get(a).getFirstDiscount().getId() == id){
									price = totalPrice - features.get(a).getFirstDiscount().getDisCount();
									disCountPrice = features.get(a).getFirstDiscount().getDisCount();
									features.get(a).getFirstDiscount().setDefDisCount(true);
								}
								disCounts.add(features.get(a).getFirstDiscount());
							}
						}
						if(features.get(a).getFirstDiscount().getType() == 4){
							if(features.get(a).getQuantity() >= features.get(a).getFirstDiscount().getThreshold()){
								if(disCountPrice == 0 && (id == null || id == 0)){
									price = totalPrice - (features.get(a).getMoney() * features.get(a).getFirstDiscount().getDisCount());
									disCountPrice = totalPrice - price;
									features.get(a).getFirstDiscount().setDefDisCount(true);
								}else if(disCountPrice == 0 && features.get(a).getFirstDiscount().getId() == id){
									price = totalPrice - (features.get(a).getMoney() * features.get(a).getFirstDiscount().getDisCount());
									disCountPrice = totalPrice - price;
									features.get(a).getFirstDiscount().setDefDisCount(true);
								}
								disCounts.add(features.get(a).getFirstDiscount());
							}
						}
					}
					if(features.get(a).getSecondDiscount() != null){
						if(features.get(a).getSecondDiscount().getType() == 1){
							if(features.get(a).getMoney() >= features.get(a).getSecondDiscount().getThreshold()){
								if(disCountPrice == 0 && (id == null || id == 0)){
									price = totalPrice - features.get(a).getSecondDiscount().getDisCount();
									disCountPrice = features.get(a).getFirstDiscount().getDisCount();
									features.get(a).getSecondDiscount().setDefDisCount(true);
								}else if(disCountPrice == 0 && features.get(a).getSecondDiscount().getId() == id){
									price = totalPrice - features.get(a).getSecondDiscount().getDisCount();
									disCountPrice = features.get(a).getFirstDiscount().getDisCount();
									features.get(a).getSecondDiscount().setDefDisCount(true);
								}
								disCounts.add(features.get(a).getSecondDiscount());
							}
						}
						if(features.get(a).getSecondDiscount().getType() == 4){
							if(features.get(a).getQuantity() >= features.get(a).getSecondDiscount().getThreshold()){
								if(disCountPrice == 0 && (id == null || id == 0)){
									price = totalPrice - (features.get(a).getMoney() * features.get(a).getSecondDiscount().getDisCount());
									disCountPrice = totalPrice - price;
									features.get(a).getSecondDiscount().setDefDisCount(true);
								}else if(disCountPrice == 0 && features.get(a).getSecondDiscount().getId() == id){
									price = totalPrice - (features.get(a).getMoney() * features.get(a).getSecondDiscount().getDisCount());
									disCountPrice = totalPrice - price;
									features.get(a).getSecondDiscount().setDefDisCount(true);
								}
								disCounts.add(features.get(a).getSecondDiscount());
							}
						}
					}
				}
			}
			countCart.put("totalPrice", totalPrice);
			countCart.put("disCountPrice", disCountPrice);
			countCart.put("price", price);
			countCart.put("disCounts", disCounts);
			return countCart;
		}
		return null;
	}
	
}
